package com.briup.common.util;


import com.github.junrar.Archive;
import com.github.junrar.rarfile.FileHeader;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ArchiveUtil {

    public static void main(String[] args) throws Exception {

//        String archiveFile = "D:/briup-online-md/upload/java.zip";
        String archiveFile = "D:/briup-online-md/upload/java.rar";
        String targetDir = "D:/briup-online-md/upload/html";
//        unzip(archiveFile,targetDir);
//        unrar(archiveFile, targetDir);
        unArchive(archiveFile,targetDir);
    }

    /**
     * rar和zip格式的都支持解压，可自动识别和切换。其他格式目前默认使用zip方式尝试解压
     * @param archiveFile 压缩文件路径
     * @param targetDir   解压到指定目标路径
     * @throws Exception
     */
    public static void unArchive(String archiveFile, String targetDir)throws Exception{
        if (archiveFile.endsWith(".rar")) {
            unrar(archiveFile,targetDir);
        }
        else if(archiveFile.endsWith(".zip")){
            unzip(archiveFile,targetDir);
        }
        else{
            //其他格式的可以尝试可以zip的方式进行解压
            unzip(archiveFile,targetDir);
        }
    }



    public static void unzip(String zipFile, String targetDir)throws Exception {
        try (ArchiveInputStream inputStream = getZipFile(new File(zipFile))) {
            File pathFile = new File(targetDir);
            if (!pathFile.exists()) {
                pathFile.mkdirs();
            }
            ArchiveEntry entry = null;
            while ((entry = inputStream.getNextEntry()) != null) {
                if (entry.isDirectory()) {
                    File directory = new File(targetDir, entry.getName());
                    directory.mkdirs();
                } else {
                    OutputStream os = null;
                    try {
                        os = new BufferedOutputStream(new FileOutputStream(new File(targetDir, entry.getName())));
                        IOUtils.copy(inputStream, os);
                    } finally {
                        IOUtils.closeQuietly(os);
                    }
                }
            }
//            final File[] files = pathFile.listFiles();
//            if (files != null && files.length == 1 && files[0].isDirectory()) {
//                // 说明只有一个文件夹
//                FileUtils.copyDirectory(files[0], pathFile);
//                //免得删除错误， 删除的文件必须在/homne/briup/briup-md/目录下。
//                boolean isValid = files[0].getPath().contains("/homne/briup/briup-md/");
//                if (isValid) {
//                    FileUtils.forceDelete(files[0]);
//                }
//            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception(e.getMessage());
        }
    }

    public static Map<String, List<String>> unzip(MultipartFile file)throws Exception {
        Map<String, List<String>> map = new HashMap<>();
        try (ArchiveInputStream inputStream = getZipFile(file)) {

            ArchiveEntry entry = null;
            String currentClassify = "";
            while ((entry = inputStream.getNextEntry()) != null) {
                String entryName = entry.getName();
                if("__MACOSX".equals(entryName) || entryName.endsWith(".DS_Store") ){
                    continue;
                }

                if (entry.isDirectory()) {
                    // 此时，entryName类似于： x/
                    currentClassify = entryName.replaceAll("/","");
                    map.put(currentClassify,new ArrayList<>());

                } else {
                    // 此时，entryName类似于： x/a.jpg
                    entryName = entryName.split("/")[entryName.split("/").length-1];
                    if(entryName.startsWith(".")){
                        continue;
                    }

                    ByteArrayOutputStream os = new ByteArrayOutputStream();
                    IOUtils.copy(inputStream, os);
                    byte[] data = os.toByteArray();
                    String imageBase64 = Base64Util.byte2Base64StringFun(data);
                    map.get(currentClassify).add(currentClassify+" "+entryName+" "+imageBase64);

                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception(e.getMessage());
        }

        return map;
    }

    private static ArchiveInputStream getZipFile(File zipFile) throws Exception {
        return new ZipArchiveInputStream(new BufferedInputStream(new FileInputStream(zipFile)));
    }

    private static ArchiveInputStream getZipFile(MultipartFile zipFile) throws Exception {
        return new ZipArchiveInputStream(new BufferedInputStream(zipFile.getInputStream()));
    }


    public static void unrar(String rarFile, String targetDir) throws Exception{

        try {
            FileOutputStream fos = null;
            // 创建一个rar档案文件
            Archive rarArchive = new Archive(new File(rarFile));
            // 判断是否有加密
            if (rarArchive != null) {
                if (rarArchive.isEncrypted()) {
                    rarArchive.close();// 关闭资源
                    throw new Exception("rar文件已被加密，无法解压");
                }
                FileHeader fileHeader = rarArchive.nextFileHeader();
                while (fileHeader != null) {
                    String name = fileHeader.getFileName();
                    name = name.replaceAll("\\\\","/");
                    String outPutFileName = targetDir + "/" + name;

                    //如果当前实体不是一个文件夹
                    if (!fileHeader.isDirectory()) {
                        //获取该文件上层目录对
                        File dir = new File(outPutFileName.substring(0, outPutFileName.lastIndexOf("/")));

                        //如果该目标不存在 或者 它不是一个目录
                        if (!dir.exists() || !dir.isDirectory()) {
                            dir.mkdirs();
                        }
                        fos = new FileOutputStream(outPutFileName);
                        // 保存解压的文件
                        rarArchive.extractFile(fileHeader, fos);
                        // 关闭资源
                        fos.close();

                    }
                    fileHeader = rarArchive.nextFileHeader();
                }
            }
            rarArchive.close();// 关闭资源
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception(e.getMessage());
        }

    }


}
